Imports System.io

Friend Class TH_firmware
    Inherits BikiSoft.Threads.BikiThread

    Const rst As Byte = 16
    Private m_data() As Byte = Nothing

    Friend Overloads Sub Execute( _
             ByVal backGroundWorker As System.ComponentModel.BackgroundWorker, _
             ByVal e As System.ComponentModel.DoWorkEventArgs)
        ' -------------------- Calls the inherited execute routine
        MyBase.Execute(backGroundWorker, e)

        OnMessage("Firmware Update Initialised")
        BikiRom_Flush()
        '        GoTo recode
start:  Dim f_ret As BK_return = BikiRom_connect(True)
        Select Case f_ret
            Case BK_return.BK_OK
                f_ret = MyClass.BikiRom_BootloaderUpload
                If f_ret <> BK_return.BK_OK And _
                  (f_ret = BK_return.BK_FAILED_INIT Or _
                   f_ret = BK_return.BK_FIRMWARE) Then

                    If BikiRom_Init(False) = BK_return.BK_OK Then
                        f_ret = Bikirom_NewBootloaderUpload()
                        If f_ret = BK_return.BK_OK Then
                            OnMessage("Firmware Update Complete")
                        End If
                    End If
                End If
                ' Do atmel reflash here!
                If f_ret = BK_return.BK_ATMEL_REQUIRES_REFLASH_12MHZ Or _
                   f_ret = BK_return.BK_ATMEL_REQUIRES_REFLASH_16MHZ Or _
                   f_ret = BK_return.BK_ATMEL_REQUIRES_REFLASH_8MHZ _
                Then
                    If BikiRom_ReCodeBootloader(f_ret) = BK_return.BK_OK Then
                        OnMessage("Firmware Update Re-Initialised")
                        GoTo start
                    End If
                End If
            Case Else
                OnMessage(Err_Decode(f_ret))
        End Select
        'm_BikiInfo.reset()
        ' BikiRom_Reset()
        close_bikirom()
    End Sub

    Private Function Bikirom_NewBootloaderUpload() As BK_return
        Dim f_Frame As Comm.Comm_Frame
        Dim f_Packet() As Byte = Nothing
        Dim Address As UShort = 0
        Dim Length As UShort = 0
        Dim cmd() As Byte = Nothing
        Dim f_speed As BK_return

        'BikiRom_Flush()
        m_BikiInfo.TimeOut = 100
        'BikiRom_Reset()
        BikiRom_BootMode()

        Threading.Thread.Sleep(10)

        Try
            f_Frame = New Comm.Comm_Frame(Comm.Comm_Frame.BikiFrameType.ID_BOOTLOADER, , , , Comm.Comm_Frame.BikiFrameType.ID_GENERAL_SPECIFIC)
            f_Frame.Send(f_Packet, True, 8)

            m_BikiInfo.TimeOut = 8000

            If Not IsNothing(f_Packet) Then
                Select Case (f_Packet(0))
                    Case &H75
                        f_speed = BK_return.BK_ATMEL_REQUIRES_REFLASH_16MHZ
                        m_data = cv_BytesFromHex(CryptResource(getResource(My.Settings.Firmware16), False).ToArray)
                    Case &H73
                        f_speed = BK_return.BK_ATMEL_REQUIRES_REFLASH_12MHZ
                        m_data = cv_BytesFromHex(CryptResource(getResource(My.Settings.Firmware12), False).ToArray)
                    Case &H71
                        f_speed = BK_return.BK_ATMEL_REQUIRES_REFLASH_8MHZ
                        m_data = cv_BytesFromHex(CryptResource(getResource(My.Settings.Firmware8), False).ToArray)
                    Case Else
                        OnMessage("Invalid Bootloader Response")
                        Return BK_return.BK_FAILED_INIT
                End Select
                OnMessage("Firmware.... Sync OK ")
                f_Frame = New Comm.Comm_Frame(Comm.Comm_Frame.BikiFrameType.ID_LAST_COMMAND_STATUS, , , , Comm.Comm_Frame.BikiFrameType.ID_LAST_COMMAND_STATUS)
                If f_Frame.Send(, False) = Comm.Comm_Frame.BikiFrameResponse.CMD_OK Then
                    OnMessage("Firmware.... Updating.... ")
                    While Address < UBound(m_data)
                        Length = (m_data(Address) * &H100) + m_data(Address + 1)

                        ReDim cmd(Length - 3)
                        Array.Copy(m_data, Address + 2, cmd, 0, Length - 2)

                        f_Frame = New Comm.Comm_Frame(Comm.Comm_Frame.BikiFrameType.ID_BOOTLOADER, , , cmd, Comm.Comm_Frame.BikiFrameType.ID_LAST_COMMAND_STATUS)
                        f_Frame.Send(, , 4)

                        OnProgress((Address / UBound(m_data)) * 100)

                        Address += Length + 2
                    End While

                Else
                    OnMessage("Bootloader Erasing Failed")
                    Return BK_return.BK_FIRMWARE
                End If

            Else
                Return BK_return.BK_FIRMWARE
            End If

            Return BK_return.BK_OK

        Catch exComm As Comm_Exceptions
            If exComm.Response = Comm.Comm_Frame.BikiFrameResponse.BOOT_FAILED Then Return f_speed
            OnMessage(exComm.Description)
            Return BK_return.BK_IO_ERROR_BIK
        Catch exUsb As USB_exceptions
            OnMessage(exUsb.Description)
            Return BK_return.BK_IO_ERROR_USB
        End Try
    End Function
    Private Function BikiRom_BootloaderUpload() As BK_return
        Dim f_packetSize As Integer = 256 'Val(txPacket.Text)
        Dim f_retBytes(0 To 20) As Byte
        Dim f_page(0 To 1) As Byte
        Dim s_error As Integer
        Dim s_crc As Integer
        Dim f_Crc As Integer
        f_Crc = f_packetSize + 1
        Dim f_returnBytes(0 To 20) As Byte
        Dim f_pageData(0 To f_packetSize + 1) As Byte
        Dim f_pageTwo(0 To f_packetSize + 1) As Byte
        Dim f_pageThree(0 To f_packetSize + 2) As Byte
        Dim f_firstByte(2) As Byte
        Dim intFirstBytes As Integer = 2
        Dim f_reflash As BK_return


        'Try
        m_BikiInfo.TimeOut = 2000
        Dim s_blEr As Integer = 0 '40
        Dim f_bytes() As Byte = Nothing
        Dim bytHeader As Byte = &HDF
        Dim f_HandshakeOk As Boolean = False

bl:
        FT_Purge(lngHandle, FT_Purg.FT_PURGE_RX)
        If s_blEr Mod 2 = 1 Then
            BikiRom_BootMode()
        Else
            BikiRom_Reset()
        End If

        'Threading.Thread.Sleep(s_blEr * 10)

        f_bytes = usb_read(1)
        If Not IsNothing(f_bytes) AndAlso f_bytes.Length > 0 Then
            If f_bytes(0) <> &HBB And _
                f_bytes(0) <> &HB1 And _
                f_bytes(0) <> &HB9 _
            Then
                s_blEr += 1
                If s_blEr > 8 Then Return BK_return.BK_FIRMWARE
                GoTo bl
            End If
        Else
            s_blEr += 1
            If s_blEr > 8 Then Return BK_return.BK_FAILED_INIT
            GoTo bl
        End If

            ' Try
            Select Case f_bytes(0)
                Case &HBB
                    f_reflash = BK_return.BK_ATMEL_REQUIRES_REFLASH_16MHZ
                    m_data = CryptResource(getResource(My.Settings.Firmware16_C), False).ToArray
                    intFirstBytes = 2
                    bytHeader = &HDF
                    f_firstByte(0) = &HDF
                    f_firstByte(1) = m_data(0)
                    f_HandshakeOk = True
                Case &HB9
                    f_reflash = BK_return.BK_ATMEL_REQUIRES_REFLASH_12MHZ
                    m_data = CryptResource(getResource(My.Settings.Firmware12_C), False).ToArray
                    'Threading.Thread.Sleep(1000)
                    usb_read(3)
                    Threading.Thread.Sleep(1000)
                    If BikiRom_hexCmd("AA55AABCEFAC", "BCEFCC") Then
                        Threading.Thread.Sleep(100)
                        If BikiRom_hexCmd("BCFECCAA55AA", "EFCABF") Then
                            intFirstBytes = 1
                            bytHeader = &HBF
                            f_firstByte(0) = m_data(0)
                            f_HandshakeOk = True
                            Threading.Thread.Sleep(100)
                            Exit Select
                        End If
                    End If
                    f_HandshakeOk = False
                Case &HB1
                    f_reflash = BK_return.BK_ATMEL_REQUIRES_REFLASH_8MHZ
                    m_data = CryptResource(getResource(My.Settings.Firmware8_C), False).ToArray
                    usb_read(3)
                    Threading.Thread.Sleep(1000)
                    If BikiRom_hexCmd("AA55AABCEFAC", "BCEFCC") Then
                        Threading.Thread.Sleep(100)
                        If BikiRom_hexCmd("BCFECCAA55AA", "EFCABF") Then
                            intFirstBytes = 1
                            bytHeader = &HBF
                            f_firstByte(0) = m_data(0)
                            f_HandshakeOk = True
                            Threading.Thread.Sleep(100)
                            Exit Select
                        End If
                    End If
                    f_HandshakeOk = False
                Case Else
                    Return BK_return.BK_BIKISOFT_REQUIRES_UPDATE
            End Select
            '  Catch
            '  Return BK_return.BK_ERROR_CATCH
            '  End Try

            f_pageData(0) = bytHeader
            f_pageTwo(0) = bytHeader
            f_pageThree(0) = bytHeader

            If m_data.Length = 0 Then
                OnMessage("Error Loading Firmware, check bikirom.com for software updates")
                Return BK_return.BK_ERROR_CATCH
            End If
            'Debug.Print("past the BB checking after wait of " & s_blEr & "ms")

            'If f_bytes(0) = 187 Then
            Threading.Thread.Sleep(100)
            OnMessage("Firmware.... Sync OK ")
            If f_HandshakeOk AndAlso BikiRom_sendCmdd(f_firstByte, f_retBytes, intFirstBytes, 1) Then
                If f_retBytes(0) = &HFF Then
                    f_bytes = usb_read(2)
                    If Not IsNothing(f_bytes) AndAlso _
                      (f_bytes(0) = &HEE And f_bytes(1) = &HFF) Then
                        Return f_reflash
                    End If
                End If
                If f_retBytes(0) = bytHeader Then
                    OnMessage("Firmware.... Updating.... ")
                    For i As Integer = 1 To UBound(m_data) Step (f_packetSize * 3)
                        array_copy(m_data, i, f_pageData, 1, f_packetSize)
                        array_copy(m_data, i + f_packetSize, f_pageTwo, 1, f_packetSize)
                        array_copy(m_data, i + (f_packetSize * 2), f_pageThree, 1, f_packetSize)
                        s_crc = 0
                        For d As Integer = 1 To (f_packetSize)
                            s_crc += CByte(f_pageData(d))
                        Next
                        For d As Integer = 1 To (f_packetSize)
                            s_crc += CByte(f_pageTwo(d))
                        Next
                        For d As Integer = 1 To (f_packetSize)
                            s_crc += CByte(f_pageThree(d))
                        Next
                        f_pageThree(f_packetSize + 1) = LOBYTE(s_crc)

reSend:                 If BikiRom_sendCmdd(f_pageData, f_retBytes, f_packetSize + 1, 1) Then
                            Debug.Print("Past 1st packet " & i)
reSend2:                    If BikiRom_sendCmdd(f_pageTwo, f_retBytes, f_packetSize + 1, 1) Then
                                Debug.Print("Past 2nd packet " & i)
reSend3:                        If BikiRom_sendCmdd(f_pageThree, f_retBytes, f_packetSize + 2, 1) = False Then
                                    OnMessage("Firmware... Updating Failed")
                                    Return BK_return.BK_FIRMWARE
                                Else
                                    Select Case f_retBytes(0)
                                        Case bytHeader
                                            s_error = 0
                                            Debug.Print(Hex(i) & " crc check ok!")
                                        Case &HDE
                                            s_error += 1
                                            If s_error >= 10 Then OnMessage("CRC ERROR # " & s_error) : Return BK_return.BK_IO_CRC_FAILED
                                            GoTo reSend
                                        Case &HEE
                                            s_error += 1
                                            If s_error >= 10 Then OnMessage("CRC ERROR # " & s_error) : Return BK_return.BK_IO_CRC_FAILED
                                            GoTo reSend3
                                    End Select
                                End If
                                ' Exit Function
                                'If (i Mod 1024) = 0 Then
                                OnProgress(((i / UBound(m_data)) * 100))
                                'End If
                            Else
                                Debug.Print("Error sending packet 2", "ERROR")
                            End If
                        Else
                            Debug.Print("Error sending packet 1", "ERROR")
                        End If
                    Next
                Else
                    GoTo bl
                    'Debug.Print("Error from initial seed byte return.. ie no return", "ERROR")
                End If
            Else
                s_blEr += 1
                If s_blEr >= 10 Then Return BK_return.BK_IO_ERROR_BIK
                GoTo bl
            End If
            Dim cmd() As Byte = cv_BytesFromHex("FF")
            If BikiRom_sendCmdd(cmd, f_retBytes, 1, 1) Then
                OnProgress(100)
                OnMessage("Firmware Update 100% OK")
                Return BK_return.BK_OK
            Else
                OnProgress(0)
                OnMessage("Firmware Updating Failed")
                Return BK_return.BK_FAILED_CMD
            End If

            BikiRom_BootMode()
            'Catch ex As Exception
            'OnMessage(Err.Description)
            'End Try
    End Function
    Private Function BikiRom_ReCodeBootloader(ByVal Speed As BK_return) As BK_return
        Dim f_flash As Byte() = Nothing
        Dim f_BLoffset As Integer = 3952
        Dim f_EEoffset As Integer = 136
        Dim f_EEprom(143) As Byte
        Dim f_code(15) As Byte
        Dim rand As New Random()

        Select Case Speed
            Case BK_return.BK_ATMEL_REQUIRES_REFLASH_12MHZ
                f_flash = CryptResource(getResource("BIKIBOOT_V1.0_12.enc"), False).ToArray
                SetUsbVariable(Biki_USBvars.UV_Baud, 375)
            Case BK_return.BK_ATMEL_REQUIRES_REFLASH_16MHZ
                f_flash = CryptResource(getResource("BIKIBOOT_V1.0_16.enc"), False).ToArray
                SetUsbVariable(Biki_USBvars.UV_Baud, 500)
            Case BK_return.BK_ATMEL_REQUIRES_REFLASH_8MHZ
                f_flash = CryptResource(getResource("BIKIBOOT_V1.0_8.enc"), False).ToArray
                SetUsbVariable(Biki_USBvars.UV_Baud, 250)
        End Select

        If IsNothing(f_flash) Then
            OnMessage("Error Re-Initialising Bikirom, contact badbiki@bikirom.com immediatley")
            Return BK_return.BK_FIRMWARE_REQUIRES_UPDATE
        End If

        For i As Integer = 0 To 12
            f_EEprom(i) = 255
        Next
        Dim f_count As Integer = 0
        For i As Integer = 1 To 8
            rand.NextBytes(f_code)
            f_count = 0
            For Each bit As Byte In f_code
                f_EEprom(f_EEoffset - (f_count * 8)) = bit
                f_count += 1
            Next
            f_BLoffset += 16
            f_EEoffset += 1
        Next
        Dim s_num(2) As Byte
        rand.NextBytes(s_num)
        f_EEprom(12) = s_num(0)
        f_EEprom(13) = s_num(1)
        f_EEprom(14) = s_num(2)
        f_EEprom(15) = 85

        close_bikirom()

        If Not IsNothing(f_flash) AndAlso SPI_Connect() AndAlso spi_reset() Then
            chipErase()
            Threading.Thread.Sleep(10)
            SPI_out(172)
            SPI_out(164)
            SPI_in()
            SPI_out(127)
            Threading.Thread.Sleep(10)
            SPI_out(172)
            SPI_out(255)
            SPI_in()
            SPI_out(205)
            SPI_disconnect()

            SetUsbVariable(Biki_USBvars.UV_BikEEPROM_CRC, 0)

            OnMessage("Firmware Pre-Initialising")

            If Not Me.setProgram(f_flash, False, True) Then OnMessage("Firmware Update Failed: Contact BadBiki Err #303") : Exit Function

            If Not Me.setEEprom(f_EEprom) Then OnMessage("Firmware Update Failed: Contact BadBiki Err #304") : Exit Function

            SPI_Connect()
            spi_reset()
            SPI_out(172)
            SPI_out(255)
            SPI_in()
            SPI_out(204)

            Threading.Thread.Sleep(10)
            SPI_disconnect()
            BikiRom_Reset()
            close_bikirom()

            Dim inp As String
            inp = InputBox("Enter the serial Number written on the back of your BikiRom USB Megaboard", "Serial Number")
            If inp <> "" Then
                inp = "BikiSoftReturnFile"
            End If
            Dim f_eeDump As New MemoryStream(f_EEprom)
            Dim f_eeDump2 As New MemoryStream

            CryptFile("This IS! not a TEST moFO But This one IS", f_eeDump, f_eeDump2, True)
            arrayDump(f_eeDump2.ToArray, Application.StartupPath & "\" & inp & ".bmd")
            MsgBox("Inside the BikiSoft Directory:" & Chr(10) _
                  & Application.StartupPath & Chr(10) _
                 & "is a file named '" & inp & ".bmd" & Chr(10) _
                 & "this needs to be emailed back to BadBiki " & Chr(10) _
                 & "at badbiki@ii.net Subject:Board Update return.. cheers", MsgBoxStyle.Information, "Infomation")

            Return BK_return.BK_OK
        End If
        close_bikirom()
        Return Speed
    End Function
    Public Function setProgram(ByRef a_data() As Byte, ByVal AutoVerify As Boolean, ByVal Program As Boolean) As Boolean
        Dim s_return As Byte
        Dim g, adr As Long
        Dim i As Long
        Dim fnum As Integer = FreeFile()
        Dim spi_enterProgMode As Byte() = {0, rst, 0}
        Dim spi_ProgrammingEnable As Byte() = {172, 83}
        Dim spi_chipErase As Byte() = {172, 128}
        Dim m_error As Integer = 0
        Dim f_genCount As Integer
        Dim f_genCmd(24575) As Byte
        Dim f_return As Integer
        ReDim Preserve a_data(&HFFF)

        If SPI_Connect() AndAlso spi_reset() Then
            For i = 126976 To 131071 Step 256
                If Not checkPageEmpty(a_data, i - 126976) Then
                    If Program = True Then
                        f_genCount = 0
                        For g = i To i + 255 Step 2
restartPageUpload:
                            adr = g \ 2

                            cmd_add(SPI_out_gen(64), f_genCmd, f_genCount)
                            cmd_add(SPI_out_gen(0), f_genCmd, f_genCount)

                            GoTo skip1
                            If SPI_in() <> 64 Then
                                m_error += 1
                                If m_error >= 100 Then
                                    Return False
                                End If
                                If Not spi_reset() Then Return False
                                GoTo restartPageUpload

                            End If
skip1:
                            cmd_add(SPI_out_gen(LOBYTE(adr)), f_genCmd, f_genCount)
                            cmd_add(SPI_out_gen(a_data(g - 126976)), f_genCmd, f_genCount)

                            cmd_add(SPI_out_gen(72), f_genCmd, f_genCount)
                            cmd_add(SPI_out_gen(0), f_genCmd, f_genCount)
                            GoTo skip2
                            If SPI_in() <> 72 Then
                                m_error += 1
                                If m_error >= 100 Then
                                    Return False
                                End If
                                If Not spi_reset() Then Return False
                                GoTo restartPageUpload

                            End If
skip2:
                            cmd_add(SPI_out_gen(LOBYTE(adr)), f_genCmd, f_genCount)
                            cmd_add(SPI_out_gen(a_data(g + 1 - 126976)), f_genCmd, f_genCount)
                        Next

                        FT_Write_Bytes(lngHandle, f_genCmd(0), 24575, f_return)

                        SPI_out(76)
                        SPI_out(HIBYTE(adr))
                        SPI_out(LOBYTE(adr))
                        s_return = SPI_in()
                        If LOBYTE(adr) <> s_return Then Debug.Print("Potenialy Failing on the Page Write command")
                        Debug.Print(s_return)
                        Threading.Thread.Sleep(20)
                    End If

                    OnProgress(((i - 126976) / 4096) * 100)
                End If
            Next
            Return True
        Else
            Return False
        End If
        OnProgress(100)
        SPI_disconnect()
        Exit Function
    End Function
    Private Sub cmd_add(ByRef f_from() As Byte, ByRef f_array() As Byte, ByRef f_count As Integer)
        array_copy(f_from, 0, f_array, f_count, f_from.Length)
        f_count += f_from.Length
    End Sub
    Public Function setEEprom(ByRef s_data() As Byte) As Boolean
        Dim i As Long
        Dim fnum As Integer = FreeFile()
        Dim spi_enterProgMode As Byte() = {0, rst, 0}
        Dim spi_ProgrammingEnable As Byte() = {172, 83}
        Dim f_sndCmd(95) As Byte
        Dim f_cmdCount As Integer
        Dim f_written As Integer

        If Not IsNothing(s_data) AndAlso SPI_Connect() AndAlso spi_reset() Then
            For i = 0 To 143
                If s_data(i) <> 255 Then
                    f_cmdCount = 0
                    cmd_add(SPI_out_gen(192), f_sndCmd, f_cmdCount)
                    cmd_add(SPI_out_gen(HIBYTE(i)), f_sndCmd, f_cmdCount)
                    cmd_add(SPI_out_gen(LOBYTE(i)), f_sndCmd, f_cmdCount)
                    cmd_add(SPI_out_gen(s_data(i)), f_sndCmd, f_cmdCount)

                    FT_Write_Bytes(lngHandle, f_sndCmd(0), 96, f_written)
                    Threading.Thread.Sleep(40)
                End If
                OnProgress((i / 143) * 100)
            Next
            Return True
        Else
            Return False
        End If
        SPI_disconnect()
    End Function

End Class
